﻿using System;
using System.Collections.Generic;

namespace JyCommonKit.ObjectPoolKit
{
    /// <summary>
    /// Simple object pool implementation.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObjectPool<T> : IDisposable
    {
        /// <summary>
        /// 最大大小
        /// </summary>
        public int DesiredSize { get { return _desiredSize; } }
        /// <summary>
        /// 对象的构造函数
        /// </summary>
        public Func<T> Constructor { get { return _constructor; } }
        /// <summary>
        /// 对象的析构函数
        /// </summary>
        public Action<T> Destructor { get { return _destructor; } }
        /// <summary>
        /// 初始化数量
        /// </summary>
        public int InitialSize { get { return _initialSize; } }

        /// <summary>
        /// 对象池的构造函数
        /// </summary>
        /// <param name="initialSize"> 初始尺寸 </param>
        /// <param name="desiredSize"> 最大尺寸 </param>
        /// <param name="constructor"> 构造函数 </param>
        /// <param name="destructor"> 析构函数 </param>
        /// <param name="lazyInitialization"> 是否需要初始化对象 </param>
        public ObjectPool(int initialSize, int desiredSize, Func<T> constructor, Action<T> destructor, bool lazyInitialization = false)
        {
            if (constructor == null)
                throw new ArgumentNullException("constructor");

            if (destructor == null)
                throw new ArgumentNullException("destructor");

            _constructor = constructor;
            _destructor = destructor;
            _desiredSize = desiredSize;
            _initialSize = initialSize;

            for (int i = 0; i < _initialSize && i < _desiredSize && !lazyInitialization; i++)
                _pool.Enqueue(_constructor());
        }

        /// <summary>
        /// 获取对象
        /// </summary>
        /// <returns> 对象 </returns>
        public T Dequeue()
        {
            if (_pool.Count > 0)
                return _pool.Dequeue();
            return _constructor();
        }

        /// <summary>
        /// 回收对象
        /// </summary>
        /// <param name="obj"> 需要回收的对象 </param>
        public void Enqueue(T obj)
        {
            if (_pool.Count < _desiredSize)
                _pool.Enqueue(obj);
            else
                _destructor(obj);
        }

        /// <summary>
        /// 置空
        /// </summary>
        public void Empty()
        {
            int count = _pool.Count;

            for (int i = 0; i < count; i++)
                _destructor(_pool.Dequeue());

            _pool.Clear();
        }

        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        /// <summary>
        /// 释放
        /// </summary>
        /// <param name="disposing"> 是否释放 </param>
        private void Dispose(bool disposing)
        {
            if (disposing && !_isDisposed)
            {
                Empty();
                _isDisposed = true;
            }
        }

        private int _desiredSize;
        private int _initialSize;
        private Func<T> _constructor;
        private Action<T> _destructor;

        private bool _isDisposed;
        private Queue<T> _pool = new Queue<T>();        
    }
}


